﻿/****************************************************************
*   作者：Morain
*   创建时间：2018/2/27 14:03:35
*   描述说明：
*****************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;

namespace ETSModel
{
  [ObjectSystem]
  public class UIComponentSystem : ObjectSystem<UIComponent>, IAwake
  {
    public void Awake()
    {
      Self.Awake();
    }
  }

  /// <summary>
  /// UI管理类
  /// </summary>
  public class UIComponent : Component
  {
    // UI根节点
    private GameObject Root;
    private readonly Dictionary<UIType, IUIFactory> uitypes = new Dictionary<UIType, IUIFactory>();
    private readonly Dictionary<UIType, UI> uis = new Dictionary<UIType, UI>();

    private readonly Dictionary<WindowLayer, GameObject> allLayers = new Dictionary<WindowLayer, GameObject>();

    public void Awake()
    {
      this.Root = GameObject.Find("Global/UI/");
      this.InstantiateUI(this.Root.transform);
      this.Load();
    }

    public void Load()
    {
      this.uitypes.Clear();
      Type[] types = DllHelper.GetAll();
      foreach (Type type in types)
      {
        object[] attrs = type.GetCustomAttributes(typeof(UIFactoryAttribute), false);
        if (attrs.Length == 0) continue;

        UIFactoryAttribute uIFactoryAttribute = attrs[0] as UIFactoryAttribute;

        if (uitypes.ContainsKey((UIType)uIFactoryAttribute.Type))
        {
          Log.Debug($"已经存在同类UI Factory: {uIFactoryAttribute.Type}");
          throw new Exception($"已经存在同类UI Factory: {uIFactoryAttribute.Type}");
        }

        object o = Activator.CreateInstance(type);
        IUIFactory uIFactory = o as IUIFactory;
        if (uIFactory == null)
        {
          Log.Error($"{o.GetType().FullName} 没有继承 IUIFactory");
          continue;
        }

        this.uitypes.Add((UIType)uIFactoryAttribute.Type, uIFactory);
      }
    }

    public UI Create(UIType type)
    {
      try
      {
        UI ui = uitypes[type].Create(type, this.Root);
        this.Add(type, ui);

        WindowLayer layer = ui.GameObject.GetComponent<UIConfig>().WindowLayer;

        this.SetViewParent(ui, layer);

        return ui;
      }
      catch (Exception e)
      {
        Log.Debug(e.ToString());
      }
      return null;
    }

    public void Add(UIType type, UI ui)
    {
      this.uis.Add(type, ui);
    }

    public void Remove(UIType type)
    {
      UI ui;
      if (!uis.TryGetValue(type, out ui))
      {
        return;
      }
      uis.Remove(type);
      ui.Dispose();
    }

    public void RemoveAll()
    {
      foreach (UIType type in this.uis.Keys.ToArray())
      {
        UI ui;
        if (!this.uis.TryGetValue(type, out ui))
        {
          continue;
        }
        this.uis.Remove(type);
        ui.Dispose();
      }
    }

    public UI Get(UIType type)
    {
      UI ui;
      this.uis.TryGetValue(type, out ui);
      return ui;
    }

    public void Show(UIType type)
    {
      UI ui;
      if (uis.TryGetValue(type, out ui)) return;

      ui.GameObject.SetActive(true);
    }

    public void Close(UIType type)
    {
      UI ui;
      if (uis.TryGetValue(type, out ui)) return;

      ui.GameObject.SetActive(false);
    }

    //初始化UI层级
    private void InstantiateUI(Transform parent)
    {
      WindowLayer[] _names = new WindowLayer[] {
                WindowLayer.UIHiden,
                WindowLayer.Bottom,
                WindowLayer.Medium,
                WindowLayer.Top,
                WindowLayer.TopMost
            };
      Camera cam = new GameObject().AddComponent<Camera>();
      cam.clearFlags = CameraClearFlags.Depth;
      cam.cullingMask = 1 << LayerMask.NameToLayer("UI");
      cam.orthographic = true;
      cam.depth = 10;
      cam.name = "UICamera";
      cam.transform.SetParent(parent);
      cam.transform.localPosition = Vector3.zero;

      foreach (var layer in _names)
      {
        var it = layer.ToString();
        GameObject _go = new GameObject();
        this.allLayers.Add(layer, _go);
        Canvas canvas = _go.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceCamera;
        canvas.worldCamera = cam;
        canvas.sortingOrder = (int)layer;
        CanvasScaler scale = _go.AddComponent<CanvasScaler>();
        scale.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        scale.referenceResolution = new Vector2(1920, 1080);
        scale.matchWidthOrHeight = 1;

        GraphicRaycaster _graphic = _go.AddComponent<GraphicRaycaster>();
        _go.name = it;
        _go.transform.SetParent(parent);
        _go.transform.localPosition = Vector3.zero;
        if (layer == WindowLayer.UIHiden)
        {
          _go.layer = LayerMask.NameToLayer("UIHiden");
          _graphic.enabled = false;
        }
        else
        {
          _go.layer = LayerMask.NameToLayer("UI");
        }
      }
    }

    //修改UI层级
    private void SetViewParent(UI ui, WindowLayer layer)
    {
      RectTransform _rt = ui.GameObject.GetComponent<RectTransform>();
      _rt.SetParent(allLayers[layer].transform);
      _rt.anchorMin = Vector2.zero;
      _rt.anchorMax = Vector2.one;
      _rt.offsetMax = Vector2.zero;
      _rt.offsetMin = Vector2.zero;
      _rt.pivot = new Vector2(0.5f, 0.5f);

      _rt.localScale = Vector3.one;
      _rt.localPosition = Vector3.zero;
      _rt.localRotation = Quaternion.identity;
    }
  }
}
